package it.tukano.swingdeco.text;

import it.tukano.fun.VFunction3;
import it.tukano.swingdeco.controls.JPopupMenuExt;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.Serializable;
import javax.swing.AbstractButton;
import javax.swing.FocusManager;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.Border;

/**
 * JTextArea extensions
 * @author pgi
 */
public class JTextAreaExt extends JTextArea implements Serializable {
    private static final KeyListener TAB_SUPPRESSOR = new KeyAdapter() {

        @Override
        public void keyPressed(KeyEvent e) {
            if(e.getKeyCode() == KeyEvent.VK_TAB) {
                e.consume();
                FocusManager.getCurrentManager().focusNextComponent();
            }
        }
    };
    private static final Border FIELD_BORDER = new JTextField().getBorder();
    private JScrollPane scroller;
    
    private final JPopupMenuExt menu = new JPopupMenuExt()
            .appendMenuItem("Copia", "copy")
            .appendMenuItem("Incolla", "paste")
            .appendMenuItem("Taglia", "cut")
            .bind(this)
            .onPopupWillBecomeVisible(new Runnable() {

                public void run() {
                    String selectedText = getSelectedText();
                    boolean empty = selectedText == null || selectedText.isEmpty();
                    menu.setButtonState("copy", !empty);
                    menu.setButtonState("cut", !empty);
                    menu.setButtonState("paste", Toolkit.getDefaultToolkit().getSystemClipboard().isDataFlavorAvailable(DataFlavor.stringFlavor));
                }
            })
            .addListener(new VFunction3<Component, Point, AbstractButton>() {

                @Override
                protected void doApply(Component p1, Point p2, AbstractButton p3) {
                    String cmd = p3.getActionCommand();
                    if("copy".equals(cmd)) {
                        copy();
                    } else if("paste".equals(cmd)) {
                        paste();
                    } else if("cut".equals(cmd)) {
                        if(getSelectedText() != null) {
                            selectAll();
                        }
                        cut();
                    }
                }
            });

    /* Serial version of this class */
    private static final long serialVersionUID = 0;

    /**
     * Instance initializer
     */
    public JTextAreaExt() {
    }
    
    public JTextAreaExt(String text) {
        super(text);
    }

    public JTextAreaExt(int rowCount, int colCount) {
        super(rowCount, colCount);
    }

    public JTextAreaExt asField() {
        setBorder(FIELD_BORDER);
        addKeyListener(TAB_SUPPRESSOR);
        return this;
    }
    
    public JScrollPane getScroller() {
        if(scroller == null) scroller = new JScrollPane(this);
        scroller.setName(getName());
        return scroller;
    }

    /**
     * Append the text version of some object
     * @param text the text to append
     * @return this
     */
    public JTextAreaExt appendText(Object text) {
        append(String.valueOf(text));
        return this;
    }

    public JTextAreaExt wrapWords() {
        setWrapStyleWord(true);
        return this;
    }

    public JTextAreaExt wrapLines() {
        setLineWrap(true);
        return this;
    }

    public JTextAreaExt editable(boolean state) {
        setEditable(state);
        return this;
    }

    public JTextAreaExt likeLabel() {
        wrapWords();
        wrapLines();
        editable(false);
        disabled();
        return this;
    }

    public JTextAreaExt disabled() {
        setBackground(Color.WHITE);
        setEnabled(false);
        return this;
    }

    public JTextAreaExt withName(String string) {
        setName(string);
        return this;
    }
}
